package com.zhang.bingmei_incomeexpenditure.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.zhang.bingmei_incomeexpenditure.config.CustomColumnWidthHandler;
import com.zhang.bingmei_incomeexpenditure.config.ForceNewRowMergeStrategy;
import com.zhang.bingmei_incomeexpenditure.entity.Utils.IECommUtil;
import com.zhang.bingmei_incomeexpenditure.entity.commom.BeanCopyUtil;
import com.zhang.bingmei_incomeexpenditure.entity.commom.R;
import com.zhang.bingmei_incomeexpenditure.entity.ie.*;
import com.zhang.bingmei_incomeexpenditure.entity.ie.selectNew.SelectDoubleResult;
import com.zhang.bingmei_incomeexpenditure.entity.ie.selectNew.SelectDoubleVO;
import com.zhang.bingmei_incomeexpenditure.entity.ie.updateNew.UpdateDoubleDTO;
import com.zhang.bingmei_incomeexpenditure.entity.ie.updateNew.UpdateDoubleVO;
import com.zhang.bingmei_incomeexpenditure.service.IncomeExpenditureService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

/**
 * @author zsj
 * @description
 * @createDate 2025/10/23 08:49
 * @Entity com.zhang.bingmei_incomeexpenditure.controller.entity.
 */
@Slf4j
@RestController
//@Api(tags = "收支情况模块相关接口")
@RequestMapping("/ie")
public class ieController {

    @Resource
    private IncomeExpenditureService incomeExpenditureService;

    //获取当前用户管辖市辖区
    @ApiOperation(value = "获取当前用户管辖市辖区")
    @ApiOperationSupport(author = "zsj")
    @PostMapping("/getDistricts")
    public R<List<CodeCityNameAndYearVO>> getDistricts(@RequestBody @Validated IncomeExpenditurePageDTO dto) {
        List<CodeCityNameAndYearVO> allCities = incomeExpenditureService.getAllDistrict(dto);
        // 处理可能的空集合
        allCities = allCities == null ? Collections.emptyList() : allCities;
        return R.ok(allCities, allCities.size());
    }

    @ApiOperation(value = "获取所有收支数据")
    @ApiOperationSupport(author = "zsj")
    @RequestMapping("/list")
    public R<List<IncomeExpenditure>> list() {
        List<IncomeExpenditure> list = incomeExpenditureService.list();
        // 查询收支表所有数据
        return R.ok(list, list.size());
    }

    //获取首页数据
    @ApiOperation(value = "获取首页数据")
    @ApiOperationSupport(author = "zsj")
    @PostMapping("/getIndexView")
    public R<List<IncomeExpenditureResult>> getIndexView(@RequestBody @Validated IncomeExpenditurePageDTO dto) {
        log.debug("getIndexView(): 获取收支情况列表，入参：dto:{}",dto);
        IncomeExpenditureResult incomeExpenditureResult = incomeExpenditureService.getIncomeExpenditureData(dto);
//        List<IncomeExpenditureDetailVO> listVO = incomeExpenditureResult.getIncomeExpenditureDetailVOList(); //原收支情况列表(不含合计)
        // 2. 用Map封装“列表数据”和“updateFlag”
        Map<String, Object> result = new HashMap<>(2);
        result.put("dataList", incomeExpenditureResult);       // 原收支情况列表(含合计)

        Boolean updateFlag = IECommUtil.isUpdateButton();
        result.put("updateFlag", updateFlag);

        log.debug("getIndexView(): 获取收支情况列表，出参：result:{}",result);
        return R.ok(result);
    }

    //获取首页数据（Double）
    @ApiOperation(value = "获取首页数据（Double）")
    @ApiOperationSupport(author = "zsj")
    @PostMapping("/getIndexViewIsDouble")
    public R<List<SelectDoubleResult>> getIndexViewIsDouble(@RequestBody @Validated IncomeExpenditurePageDTO dto) {
        log.debug("getIndexView(): 获取收支情况列表，入参：dto:{}",dto);
        SelectDoubleResult incomeExpenditureResult = incomeExpenditureService.getIncomeExpenditureDoubleData(dto);
//        List<IncomeExpenditureDetailVO> listVO = incomeExpenditureResult.getIncomeExpenditureDetailVOList(); //原收支情况列表(不含合计)
        // 2. 用Map封装“列表数据”和“updateFlag”
        Map<String, Object> result = new HashMap<>(2);
        result.put("dataList", incomeExpenditureResult);       // 原收支情况列表(含合计)

        Boolean updateFlag = IECommUtil.isUpdateButton();
        result.put("updateFlag", updateFlag);

        log.debug("getIndexView(): 获取收支情况列表，出参：result:{}",result);
        int size = incomeExpenditureResult.getSelectDoubleResults().size();
        return R.ok(result,size);
    }


    @PostMapping("/getAllIEData")
    public R<List<IncomeExpenditure>> getAllIEData(@RequestBody @Validated IncomeExpenditurePageDTO dto) {
        SelectDoubleResult incomeExpenditureResult = incomeExpenditureService.getAllIEData(dto);
        Map<String, Object> result = new HashMap<>(2);
        result.put("dataList", incomeExpenditureResult);       // 原收支情况列表(含合计)

        Boolean updateFlag = IECommUtil.isUpdateButton();
        result.put("updateFlag", updateFlag);

        log.debug("getAllIEData(): 获取收支情况列表，出参：result:{}",result);
        int size = incomeExpenditureResult.getSelectDoubleResults().size();
        return R.ok(result,size);
    }

    //修改
    @PostMapping("/updateIncomeExpenditure")
    public R<List<IncomeExpenditureDetailVO>> updateIncomeExpenditureList(@RequestBody @Validated List<UpdateIncomeExpenditureDTO> updateList) {
        log.debug("updateIncomeExpenditureList(): 修改收支情况列表，入参：updateList:{}",updateList);
        List<IncomeExpenditureDetailVO> listVO = incomeExpenditureService.batchUpdateIncomeExpenditureData(updateList);

        // 2. 用Map封装“列表数据”和“updateFlag”
        Map<String, Object> result = new HashMap<>(2);
        result.put("dataList", listVO);       // 原收支情况列表

        Boolean updateFlag = IECommUtil.isUpdateButton();
        result.put("updateFlag", updateFlag);

        log.debug("updateIncomeExpenditureList(): 获取收支情况列表，出参：result:{}",result);
        return R.ok(result);
    }

    //修改（Double）
    @PostMapping("/updateNew")
    public R<List<UpdateDoubleVO>> updateNew(@RequestBody @Validated List<UpdateDoubleDTO> dataList) {
        List<UpdateDoubleVO> updateDoubleVOS = incomeExpenditureService.batchUpdateIncomeExpenditureDataLong(dataList);
        return R.ok(updateDoubleVOS);
    }
    //TODO：修改 + 新增
    @PostMapping("/updateIncomeExpenditureList")
    public R<List<IncomeExpenditureDetailVO>> updateOrInsertIE(@RequestBody @Validated List<UpdateOrInsertIEDTO> dataList) {
        log.debug("updateOrInsertIE(): 修改收支情况列表，入参：dataList:{}",dataList);
        incomeExpenditureService.updateOrInsertIE(dataList);
        return R.ok();
    }

    /**
     * 导出
     * @param dto
     * @param response
     */


    //导出
    @PostMapping("/exportIncomeExpenditure")
    R<IncomeExpenditureResult2> exportIncomeExpenditure(@RequestBody @Validated IncomeExpenditurePageDTO dto, HttpServletResponse response) throws Exception {
        //获取数据
        IncomeExpenditureResult oldData = incomeExpenditureService.getIncomeExpenditureData(dto);
        //数据封装
        IncomeExpenditureResult2 exportResultData = new IncomeExpenditureResult2();
        List<IncomeExpenditureExportVO> list = BeanCopyUtil.copyListToList(oldData.getIncomeExpenditureDetailVOList(), IncomeExpenditureExportVO.class);
        exportResultData.setIncomeExpenditureExportVOList(list);
        exportResultData.setIncomeExpenditureTotalSum(oldData.getIncomeExpenditureTotalSum());
        log.debug("exportIncomeExpenditure(): 导出收支情况列表，入参：dto:{}",dto);
        log.debug("exportIncomeExpenditure(): 导出收支情况列表，查询数据：oldData:{}",oldData);
        log.debug("exportIncomeExpenditure(): 导出收支情况列表，导出数据：exportResultData:{}",exportResultData);

        String fileName = "file/fillexcel/IE-template.xlsx";
        InputStream templateStream = getClass().getClassLoader().getResourceAsStream(File.separatorChar + fileName);
        int flag = -1;
        if ((templateStream == null || templateStream.available() <= 0) && flag == -1 ) {
            //这里如果获取不到的话，可以使用仓库相对路径去读取
            templateStream = this.getClass().getClassLoader().getResourceAsStream("vector-module/vector-admin/src/main/resources/IE-template.xlsx");
            flag = 1;
        }
        //双判文件
        if (templateStream == null || templateStream.available() <= 0 && flag == 1) {
            log.error("收支情况导出模板文件不存在: {}", fileName);
            throw new RuntimeException("支情况导出模板文件不存在");
        }

        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment; filename=example.xlsx");
        ServletOutputStream outputStream = response.getOutputStream();
        // ---------- 1. 准备 Map（非列表部分） ----------
        Map<String, Object> dataMap = new HashMap<>();
        IncomeExpenditurePageDTO formatDto = IECommUtil.getDTO(dto);
        dataMap.put("startDate", formatDto.getStartDateStr());
        dataMap.put("endDate", formatDto.getEndDateStr());
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> sumMap = mapper.convertValue(exportResultData.getIncomeExpenditureTotalSum(), Map.class);
        dataMap.putAll(sumMap);
        // ---------- 2. 准备 List（列表部分） ----------
        List<IncomeExpenditureExportVO> detailList = exportResultData.getIncomeExpenditureExportVOList();
        // ---------- 3. 写出 ----------
        //创建自定义合并规则（这里注意版本问题！！！被坑了）
        ForceNewRowMergeStrategy mergeStrategy = new ForceNewRowMergeStrategy(0, new int[]{0});
        ExcelWriter excelWriter = EasyExcel.write(outputStream)
                .withTemplate(templateStream)
                .excelType(ExcelTypeEnum.XLSX)
                .build();
        //这一行必须加：否则会遇见占位符覆盖的现象，这个比较恶心，会导致最后一行合计无法正常显示
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        WriteSheet writeSheet = EasyExcel.writerSheet()
                //应用合并规则
                .registerWriteHandler(mergeStrategy)
                .build();
        // 关键：分两次 fill
        // 合计、日期等普通占位符
        excelWriter.fill(dataMap, writeSheet);
        // 列表占位符  如果是多个的话，就会用到这个FillWrapper，我这是为了做演示，就给你加了一下，对应的模板也对应加了一下
        excelWriter.fill(new FillWrapper("data", detailList), fillConfig, writeSheet);
        excelWriter.finish();
        return R.ok(exportResultData);
    }

    //导出（Double）
    @PostMapping("/exportExcel")
    void exportExcel(@RequestBody @Validated IncomeExpenditurePageDTO dto, HttpServletResponse response) throws Exception {
        //获取数据
        SelectDoubleResult oldData = incomeExpenditureService.getAllIEData(dto);
        //数据封装
        SelectDoubleResult exportResultData = new SelectDoubleResult();
        List<SelectDoubleVO> list = BeanCopyUtil.copyListToList(oldData.getSelectDoubleResults(), SelectDoubleVO.class);
        exportResultData.setSelectDoubleResults(list);
        exportResultData.setSelectDoubleSum(oldData.getSelectDoubleSum());
        log.debug("exportIncomeExpenditure(): 导出收支情况列表，入参：dto:{}",dto);
        log.debug("exportIncomeExpenditure(): 导出收支情况列表，查询数据：oldData:{}",oldData);
        log.debug("exportIncomeExpenditure(): 导出收支情况列表，导出数据：exportResultData:{}",exportResultData);

        String fileName = "file/fillexcel/IE-template2.xlsx";
        InputStream templateStream = getClass().getClassLoader().getResourceAsStream(File.separatorChar + fileName);
        int flag = -1;
        if ((templateStream == null || templateStream.available() <= 0) && flag == -1 ) {
            //这里如果获取不到的话，可以使用仓库相对路径去读取
            templateStream = this.getClass().getClassLoader().getResourceAsStream("vector-module/vector-admin/src/main/resources/IE-template.xlsx");
            flag = 1;
        }
        //双判文件
        if (templateStream == null || templateStream.available() <= 0 && flag == 1) {
            log.error("收支情况导出模板文件不存在: {}", fileName);
            throw new RuntimeException("支情况导出模板文件不存在");
        }

        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment; filename=example.xlsx");
        ServletOutputStream outputStream = response.getOutputStream();
        // ---------- 1. 准备 Map（非列表部分） ----------
        Map<String, Object> dataMap = new HashMap<>();

        IncomeExpenditurePageDTO formatDto = IECommUtil.getDTO(dto);
        dataMap.put("startDate", formatDto.getStartDateStr());
        dataMap.put("endDate", formatDto.getEndDateStr());
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> sumMap = mapper.convertValue(exportResultData.getSelectDoubleSum(), Map.class);

        dataMap.putAll(sumMap);
        // ---------- 2. 准备 List（列表部分） ----------
        List<SelectDoubleVO> detailList = exportResultData.getSelectDoubleResults();
        // ---------- 3. 写出 ----------

        Map<Integer, Integer> columnWidthMap = new HashMap<>();
        columnWidthMap.put(0, 22);  // 0: 市辖区
        columnWidthMap.put(1, 10);  // 1: 年度
        columnWidthMap.put(2, 16);  // 2: 市级下拨经费
        columnWidthMap.put(3, 16);  // 3: 区级配套经费
        columnWidthMap.put(4, 22);  // 4: 其他（财政专项、单位自筹等）
        columnWidthMap.put(5, 16);  // 5: 经费来源合计
        columnWidthMap.put(6, 28);  // 6: 购置、维修、维护“防蚊、防蚊蝇”设施支出
        columnWidthMap.put(7, 22);  // 7: 购买消杀设备、药品支出
        columnWidthMap.put(8, 26);  // 8: 病媒生物防制相关宣传费、印刷费
        columnWidthMap.put(9, 30);  // 9: 组织专家开展区内病媒防制工作研讨等支出
        columnWidthMap.put(10, 24); // 10: 购买第三方病媒防制服务支出
        columnWidthMap.put(11, 22); // 11: 其他不属于上述用途的支出
        columnWidthMap.put(12, 18); // 12: 已实际完成支付合计
        columnWidthMap.put(13, 18); // 13: 被收回的市级下拨经费
        columnWidthMap.put(14, 18); // 14: 被收回的区级配套经费

        CustomColumnWidthHandler columnWidthHandler = new CustomColumnWidthHandler(columnWidthMap); // 自定义列宽处理器

        //创建自定义合并规则（这里注意版本问题！！！被坑了）
        ForceNewRowMergeStrategy mergeStrategy = new ForceNewRowMergeStrategy(0, new int[]{0});

        ExcelWriter excelWriter = EasyExcel.write(outputStream)
                .withTemplate(templateStream)
                .excelType(ExcelTypeEnum.XLSX)
                .build();
        //这一行必须加：否则会遇见占位符覆盖的现象，这个比较恶心，会导致最后一行合计无法正常显示
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        WriteSheet writeSheet = EasyExcel.writerSheet()
                //应用合并规则
                .registerWriteHandler(mergeStrategy)
                .registerWriteHandler(columnWidthHandler) // 注册列宽处理器
                .build();
        // 关键：分两次 fill
        // 合计、日期等普通占位符
        excelWriter.fill(dataMap, writeSheet);
        // 列表占位符  如果是多个的话，就会用到这个FillWrapper，我这是为了做演示，就给你加了一下，对应的模板也对应加了一下
        excelWriter.fill(new FillWrapper("data", detailList), fillConfig, writeSheet);
        excelWriter.finish();
    }

    //导出（Double）
    @PostMapping("/export1")
    R<IncomeExpenditureResult2> exportExcel1(@RequestBody @Validated IncomeExpenditurePageDTO dto, HttpServletResponse response) throws Exception {
        //获取数据
        SelectDoubleResult oldData = incomeExpenditureService.getAllIEData(dto);
        //数据封装
        SelectDoubleResult exportResultData = new SelectDoubleResult();
        List<SelectDoubleVO> list = BeanCopyUtil.copyListToList(oldData.getSelectDoubleResults(), SelectDoubleVO.class);
        exportResultData.setSelectDoubleResults(list);
        exportResultData.setSelectDoubleSum(oldData.getSelectDoubleSum());
        log.debug("exportIncomeExpenditure(): 导出收支情况列表，入参：dto:{}",dto);
        log.debug("exportIncomeExpenditure(): 导出收支情况列表，查询数据：oldData:{}",oldData);
        log.debug("exportIncomeExpenditure(): 导出收支情况列表，导出数据：exportResultData:{}",exportResultData);

        String fileName = "file/fillexcel/IE-template.xlsx";
        InputStream templateStream = getClass().getClassLoader().getResourceAsStream(File.separatorChar + fileName);
        int flag = -1;
        if ((templateStream == null || templateStream.available() <= 0) && flag == -1 ) {
            //这里如果获取不到的话，可以使用仓库相对路径去读取
            templateStream = this.getClass().getClassLoader().getResourceAsStream("vector-module/vector-admin/src/main/resources/IE-template.xlsx");
            flag = 1;
        }
        //双判文件
        if (templateStream == null || templateStream.available() <= 0 && flag == 1) {
            log.error("收支情况导出模板文件不存在: {}", fileName);
            throw new RuntimeException("收支情况导出模板文件不存在");
        }

        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment; filename=example.xlsx");
        ServletOutputStream outputStream = response.getOutputStream();
        // ---------- 1. 准备 Map（非列表部分） ----------
        Map<String, Object> dataMap = new HashMap<>();

        IncomeExpenditurePageDTO formatDto = IECommUtil.getDTO(dto);
        dataMap.put("startDate", formatDto.getStartDateStr());
        dataMap.put("endDate", formatDto.getEndDateStr());
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> sumMap = mapper.convertValue(exportResultData.getSelectDoubleSum(), Map.class);

        dataMap.putAll(sumMap);
        // ---------- 2. 准备 List（列表部分） ----------
        List<SelectDoubleVO> detailList = exportResultData.getSelectDoubleResults();
        // ---------- 3. 写出 ----------

        Map<Integer, Integer> columnWidthMap = new HashMap<>();
        columnWidthMap.put(0, 22);  // 0: 市辖区
        columnWidthMap.put(1, 10);  // 1: 年度
        columnWidthMap.put(2, 16);  // 2: 市级下拨经费
        columnWidthMap.put(3, 16);  // 3: 区级配套经费
        columnWidthMap.put(4, 22);  // 4: 其他（财政专项、单位自筹等）
        columnWidthMap.put(5, 16);  // 5: 经费来源合计
        columnWidthMap.put(6, 28);  // 6: 购置、维修、维护“防蚊、防蚊蝇”设施支出
        columnWidthMap.put(7, 22);  // 7: 购买消杀设备、药品支出
        columnWidthMap.put(8, 26);  // 8: 病媒生物防制相关宣传费、印刷费
        columnWidthMap.put(9, 30);  // 9: 组织专家开展区内病媒防制工作研讨等支出
        columnWidthMap.put(10, 24); // 10: 购买第三方病媒防制服务支出
        columnWidthMap.put(11, 22); // 11: 其他不属于上述用途的支出
        columnWidthMap.put(12, 18); // 12: 已实际完成支付合计
        columnWidthMap.put(13, 18); // 13: 被收回的市级下拨经费
        columnWidthMap.put(14, 18); // 14: 被收回的区级配套经费

        CustomColumnWidthHandler columnWidthHandler = new CustomColumnWidthHandler(columnWidthMap); // 自定义列宽处理器

        //创建自定义合并规则（这里注意版本问题！！！被坑了）
        ForceNewRowMergeStrategy mergeStrategy = new ForceNewRowMergeStrategy(0, new int[]{0});

        ExcelWriter excelWriter = EasyExcel.write(outputStream)
                .withTemplate(templateStream)
                .excelType(ExcelTypeEnum.XLSX)
                .build();
        //这一行必须加：否则会遇见占位符覆盖的现象，这个比较恶心，会导致最后一行合计无法正常显示
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        WriteSheet writeSheet = EasyExcel.writerSheet()
                //应用合并规则
                .registerWriteHandler(mergeStrategy)
                .registerWriteHandler(columnWidthHandler) // 注册列宽处理器
                .build();
        // 关键：分两次 fill
        // 合计、日期等普通占位符
        excelWriter.fill(dataMap, writeSheet);
        // 列表占位符  如果是多个的话，就会用到这个FillWrapper，我这是为了做演示，就给你加了一下，对应的模板也对应加了一下
        excelWriter.fill(new FillWrapper("data", detailList), fillConfig, writeSheet);
        excelWriter.finish();
        return R.ok(exportResultData);
    }

    //导出（Double）
/*    //导出（Double）
    @PostMapping("/exportExcel")
    public void exportExcel(@RequestBody @Validated IncomeExpenditurePageDTO dto,
                            HttpServletResponse response,
                            HttpServletRequest request) {
        ServletOutputStream outputStream = null;
        InputStream templateStream = null;
        try {
            // 1. 获取并封装数据（不变）
            SelectDoubleResult oldData = incomeExpenditureService.getAllIEData(dto);
            SelectDoubleResult exportResultData = new SelectDoubleResult();
            List<SelectDoubleVO> list = BeanCopyUtil.copyListToList(oldData.getSelectDoubleResults(), SelectDoubleVO.class);
            exportResultData.setSelectDoubleResults(list);
            exportResultData.setSelectDoubleSum(oldData.getSelectDoubleSum());

            log.debug("导出收支情况列表，入参：dto:{}", dto);
            log.debug("导出数据量：{}", list.size());

            // 2. 读取模板文件（不变）
            String templateFileName = "IE-template.xlsx";
            templateStream = getClass().getClassLoader().getResourceAsStream(templateFileName);
            if (templateStream == null) {
                templateStream = getClass().getClassLoader().getResourceAsStream("vector-module/vector-admin/src/main/resources/" + templateFileName);
            }
            if (templateStream == null || templateStream.available() <= 0) {
                log.error("模板文件不存在: {}", templateFileName);
                throw new RuntimeException("收支情况导出模板文件不存在");
            }

            // 3. 解决文件名乱码（核心修改：使用W3C标准格式，兼容所有浏览器）
            String exportFileName = "收支情况表.xlsx";
            // UTF-8编码文件名，再拼接成W3C标准格式
            String encodedFileName = URLEncoder.encode(exportFileName, "UTF-8");
            // 关键：用 filename*=UTF-8'' 格式，而非 filename=
            response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + encodedFileName);

            // 4. 其他响应头配置（不变）
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Pragma", "public");
            response.setHeader("Cache-Control", "max-age=0");
            outputStream = response.getOutputStream();

            // 5. 准备填充数据（不变）
            Map<String, Object> dataMap = new HashMap<>();
            IncomeExpenditurePageDTO formatDto = IECommUtil.getDTO(dto);
            dataMap.put("startDate", formatDto.getStartDateStr());
            dataMap.put("endDate", formatDto.getEndDateStr());

            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> sumMap = mapper.convertValue(exportResultData.getSelectDoubleSum(), Map.class);
            dataMap.putAll(sumMap);

            List<SelectDoubleVO> detailList = exportResultData.getSelectDoubleResults();

            // 6. 列宽配置（不变）
            Map<Integer, Integer> columnWidthMap = new HashMap<>();
            columnWidthMap.put(0, 22);  // 0: 市辖区
            columnWidthMap.put(1, 10);  // 1: 年度
            columnWidthMap.put(2, 16);  // 2: 市级下拨经费
            columnWidthMap.put(3, 16);  // 3: 区级配套经费
            columnWidthMap.put(4, 22);  // 4: 其他（财政专项、单位自筹等）
            columnWidthMap.put(5, 16);  // 5: 经费来源合计
            columnWidthMap.put(6, 28);  // 6: 购置、维修、维护“防蚊、防蚊蝇”设施支出
            columnWidthMap.put(7, 22);  // 7: 购买消杀设备、药品支出
            columnWidthMap.put(8, 26);  // 8: 病媒生物防制相关宣传费、印刷费
            columnWidthMap.put(9, 30);  // 9: 组织专家开展区内病媒防制工作研讨等支出
            columnWidthMap.put(10, 24); // 10: 购买第三方病媒防制服务支出
            columnWidthMap.put(11, 22); // 11: 其他不属于上述用途的支出
            columnWidthMap.put(12, 18); // 12: 已实际完成支付合计
            columnWidthMap.put(13, 18); // 13: 被收回的市级下拨经费
            columnWidthMap.put(14, 18); // 14: 被收回的区级配套经费

            // 7. 初始化处理器（不变）
            CustomColumnWidthHandler columnWidthHandler = new CustomColumnWidthHandler(columnWidthMap);
            ForceNewRowMergeStrategy mergeStrategy = new ForceNewRowMergeStrategy(0, new int[]{0});

            // 8. 写入Excel（不变）
            ExcelWriter excelWriter = EasyExcel.write(outputStream)
                    .withTemplate(templateStream)
                    .excelType(ExcelTypeEnum.XLSX)
                    .build();

            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            WriteSheet writeSheet = EasyExcel.writerSheet()
                    .registerWriteHandler(mergeStrategy)
                    .registerWriteHandler(columnWidthHandler)
                    .build();

            excelWriter.fill(dataMap, writeSheet);
            excelWriter.fill(new FillWrapper("data", detailList), fillConfig, writeSheet);
            excelWriter.finish();
            outputStream.flush();

            log.info("Excel导出成功，文件名：{}", encodedFileName);

        } catch (Exception e) {
            log.error("Excel导出失败", e);
            try {
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"code\":500,\"msg\":\"导出失败：" + e.getMessage() + "\"}");
            } catch (IOException ex) {
                log.error("异常信息写入响应失败", ex);
            }
        } finally {
            // 关闭资源（不变）
            try {
                if (outputStream != null) outputStream.close();
                if (templateStream != null) templateStream.close();
            } catch (IOException e) {
                log.error("流关闭失败", e);
            }
        }
    }*/

    /*//导出测试
    @PostMapping("/export")
    public void export(@RequestBody @Validated IncomeExpenditurePageDTO dto, HttpServletResponse response) throws IOException {

        if (dto.hasEmptyDates()) {
            dto.initDefaultDates();
        }

        InputStream templateFileName = null;
        try{
            templateFileName = new ClassPathResource("template/fillexcel/IncomeExpenditure-template.xlsx").getInputStream();
        } catch (IOException e) {
            throw new RuntimeException("模版异常"+e.getMessage());
        }

        // 获取响应对象并设置响应头
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("收支测试模板导出", "utf-8") + ".xlsx");
        ServletOutputStream out = response.getOutputStream();

        // 构建 ExcelWriter 并写入数据
        ExcelWriter excelWriter = EasyExcel.write(out).withTemplate(templateFileName).build();
        try{
            WriteSheet writeSheet = EasyExcel.writerSheet().build();

            // 构造模板中需要填充的参数（示例：根据实际模板变量调整）
            Map<String, Object> map = new HashMap<>();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
            map.put("startDate", sdf.format(dto.getStartDate()));
            map.put("endDate", sdf.format(dto.getEndDate())); // key与模板变量{endDate}一致

            List<IncomeExpenditure> incomeExpenditures = incomeExpenditureService.getAllData();
            List<IncomeExpenditureExportVO> exportVOList = BeanCopyUtil.copyListToList(incomeExpenditures, IncomeExpenditureExportVO.class);
            System.out.println("导出列表大小：" + exportVOList.size()); // 若为0，需检查service层数据查询逻辑
            if (!exportVOList.isEmpty()) {
                System.out.println("第一条数据：" + exportVOList.get(0)); // 确认字段有值
                System.out.println("最后一条数据：" + exportVOList.get(exportVOList.size() - 1));
            }

            //封装各列的合计数据返回前端
            IncomeExpenditureTotalSum sum = new IncomeExpenditureTotalSum();
            //设置合计值（为导出的合计数据做准备）
            sum.setCityAllocatedSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getCityAllocated).sum());
            sum.setDistrictAllocatedSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getDistrictAllocated).sum());
            sum.setOtherFundsSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getOtherFunds).sum());
            sum.setTotalFundsSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getTotalFunds).sum());
            sum.setPurchaseMaintainSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getPurchaseMaintain).sum());
            sum.setPurchaseEquipmentSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getPurchaseEquipment).sum());
            sum.setDiseasePreventionSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getDiseasePrevention).sum());
            sum.setExpertTrainingSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getExpertTraining).sum());
            sum.setThirdPartyServiceSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getThirdPartyService).sum());
            sum.setOtherPaymentSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getOtherPayment).sum());
            sum.setTotalPaymentSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getTotalPayment).sum());
            sum.setCityRecoveredSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getCityRecovered).sum());
            sum.setDistrictRecoveredSum(incomeExpenditures.stream().mapToLong(IncomeExpenditure::getDistrictRecovered).sum());

            // IEResult封装返回数据
            IncomeExpenditureResult2 result = new IncomeExpenditureResult2();
            result.setIncomeExpenditureExportVOList(exportVOList);
            result.setIncomeExpenditureTotalSum(sum);

            System.out.println("IEResult：" + result);
            // 填充模板参数
            excelWriter.fill(map, writeSheet);
            excelWriter.fill(result.getIncomeExpenditureExportVOList(), FillConfig.builder().forceNewRow(Boolean.TRUE).build(),writeSheet);//不是最后一行
            excelWriter.fill(result.getIncomeExpenditureTotalSum(), writeSheet);
        } catch (Exception e) {
            throw new RuntimeException("Excel 导出失败：" + e.getMessage());
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (templateFileName != null) {
                try {
                    templateFileName.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 手动关闭资源
            if (excelWriter != null) {
                excelWriter.finish(); // EasyExcel 推荐用 finish() 关闭，内部会处理流释放
            }
        }
    }*/

    /**
     * 导出收支数据到Excel（基于模板填充）
     */
/*    @PostMapping("/export1")
    public void export1(@RequestBody @Validated IncomeExpenditurePageDTO dto, HttpServletResponse response, Writer writer) throws Exception {
        // 1. 处理默认日期
        if (dto.hasEmptyDates()) {
            dto.initDefaultDates();
        }

        //加载模版
        InputStream exportTemplate = ieController.class.getClassLoader().getResourceAsStream("template/fillexcel/demo-template.xlsx");

        try(ExcelWriter excelWriter = EasyExcel.write("C:\\Users\\zhang\\Desktop\\flies\\demo.xlsx").withTemplate(exportTemplate).build();){

            WriteSheet writerSheet = EasyExcel.writerSheet().build();

            //公司信息
            Map<String, Object> companyInfo = new HashMap<>();
            companyInfo.put("companyInfo", "海南xxx有限公司");
            excelWriter.fill(companyInfo,writerSheet);
        }

    }*/


   /* @PostMapping("export-haikou1")
    public void exportHaikou1(@RequestBody @Validated IncomeExpenditurePageDTO dto, HttpServletResponse response) throws Exception {

        System.out.println("进来了export-haikou2");
        // 1. 设置响应头
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Type", "application/vnd.ms-excel");
        String fileName = URLEncoder.encode("海口市病媒生物防制工作经费收支情况统计表_" + DateUtil.format(new Date(), "yyyyMMdd"), "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");

        // 2. 构造模拟数据（完全匹配实体类字段）
        List<IncomeExpenditure> dataList = incomeExpenditureService.getAllData();
        dataList.forEach(System.out::println);

        // 3. 转换为导出VO（严格匹配实体类字段映射）
        List<HaikouIncomeExpenditureExportVO> exportList = dataList.stream().map(entity -> {
            HaikouIncomeExpenditureExportVO vo = new HaikouIncomeExpenditureExportVO();
            vo.setDistrict(entity.getDistrict());
            vo.setYear(entity.getYear());
            vo.setCityAllocated(entity.getCityAllocated());
            vo.setDistrictAllocated(entity.getDistrictAllocated());
            vo.setOtherFunds(entity.getOtherFunds());
            vo.setFundsSourceTotal(entity.getTotalFunds());
            vo.setPurchaseMaintain(entity.getPurchaseMaintain());
            vo.setPurchaseEquipment(entity.getPurchaseEquipment());
            vo.setDiseasePrevention(entity.getDiseasePrevention());
            vo.setExpertTraining(entity.getExpertTraining());
            vo.setThirdPartyService(entity.getThirdPartyService());
            vo.setOtherPayment(entity.getOtherPayment());
            vo.setPaymentTotal(entity.getTotalPayment());
            vo.setCityRecovered(entity.getCityRecovered());
            vo.setDistrictRecovered(entity.getDistrictRecovered());
            return vo;
        }).collect(Collectors.toList());

        // 4. 计算分组合计与总计行
        Map<String, HaikouIncomeExpenditureExportVO> groupSumMap = new HashMap<>();
        HaikouIncomeExpenditureExportVO totalSum = new HaikouIncomeExpenditureExportVO();
        totalSum.setDistrict("合计");
        totalSum.setYear(null);

        for (HaikouIncomeExpenditureExportVO vo : exportList) {
            String key = vo.getDistrict() + "_" + vo.getYear();
            if (!groupSumMap.containsKey(key)) {
                groupSumMap.put(key, new HaikouIncomeExpenditureExportVO());
                groupSumMap.get(key).setDistrict(vo.getDistrict());
                groupSumMap.get(key).setYear(vo.getYear());
            }
            HaikouIncomeExpenditureExportVO groupSum = groupSumMap.get(key);
            // 累加各字段（空值处理）
            groupSum.setCityAllocated(Objects.isNull(groupSum.getCityAllocated()) ? vo.getCityAllocated() : groupSum.getCityAllocated() + vo.getCityAllocated());
            groupSum.setDistrictAllocated(Objects.isNull(groupSum.getDistrictAllocated()) ? vo.getDistrictAllocated() : groupSum.getDistrictAllocated() + vo.getDistrictAllocated());
            groupSum.setOtherFunds(Objects.isNull(groupSum.getOtherFunds()) ? vo.getOtherFunds() : groupSum.getOtherFunds() + vo.getOtherFunds());
            groupSum.setFundsSourceTotal(Objects.isNull(groupSum.getFundsSourceTotal()) ? vo.getFundsSourceTotal() : groupSum.getFundsSourceTotal() + vo.getFundsSourceTotal());
            groupSum.setPurchaseMaintain(Objects.isNull(groupSum.getPurchaseMaintain()) ? vo.getPurchaseMaintain() : groupSum.getPurchaseMaintain() + vo.getPurchaseMaintain());
            groupSum.setPurchaseEquipment(Objects.isNull(groupSum.getPurchaseEquipment()) ? vo.getPurchaseEquipment() : groupSum.getPurchaseEquipment() + vo.getPurchaseEquipment());
            groupSum.setDiseasePrevention(Objects.isNull(groupSum.getDiseasePrevention()) ? vo.getDiseasePrevention() : groupSum.getDiseasePrevention() + vo.getDiseasePrevention());
            groupSum.setExpertTraining(Objects.isNull(groupSum.getExpertTraining()) ? vo.getExpertTraining() : groupSum.getExpertTraining() + vo.getExpertTraining());
            groupSum.setThirdPartyService(Objects.isNull(groupSum.getThirdPartyService()) ? vo.getThirdPartyService() : groupSum.getThirdPartyService() + vo.getThirdPartyService());
            groupSum.setOtherPayment(Objects.isNull(groupSum.getOtherPayment()) ? vo.getOtherPayment() : groupSum.getOtherPayment() + vo.getOtherPayment());
            groupSum.setPaymentTotal(Objects.isNull(groupSum.getPaymentTotal()) ? vo.getPaymentTotal() : groupSum.getPaymentTotal() + vo.getPaymentTotal());
            groupSum.setCityRecovered(Objects.isNull(groupSum.getCityRecovered()) ? vo.getCityRecovered() : groupSum.getCityRecovered() + vo.getCityRecovered());
            groupSum.setDistrictRecovered(Objects.isNull(groupSum.getDistrictRecovered()) ? vo.getDistrictRecovered() : groupSum.getDistrictRecovered() + vo.getDistrictRecovered());

            // 累加总计行
            totalSum.setCityAllocated(Objects.isNull(totalSum.getCityAllocated()) ? vo.getCityAllocated() : totalSum.getCityAllocated() + vo.getCityAllocated());
            totalSum.setDistrictAllocated(Objects.isNull(totalSum.getDistrictAllocated()) ? vo.getDistrictAllocated() : totalSum.getDistrictAllocated() + vo.getDistrictAllocated());
            totalSum.setOtherFunds(Objects.isNull(totalSum.getOtherFunds()) ? vo.getOtherFunds() : totalSum.getOtherFunds() + vo.getOtherFunds());
            totalSum.setFundsSourceTotal(Objects.isNull(totalSum.getFundsSourceTotal()) ? vo.getFundsSourceTotal() : totalSum.getFundsSourceTotal() + vo.getFundsSourceTotal());
            totalSum.setPurchaseMaintain(Objects.isNull(totalSum.getPurchaseMaintain()) ? vo.getPurchaseMaintain() : totalSum.getPurchaseMaintain() + vo.getPurchaseMaintain());
            totalSum.setPurchaseEquipment(Objects.isNull(totalSum.getPurchaseEquipment()) ? vo.getPurchaseEquipment() : totalSum.getPurchaseEquipment() + vo.getPurchaseEquipment());
            totalSum.setDiseasePrevention(Objects.isNull(totalSum.getDiseasePrevention()) ? vo.getDiseasePrevention() : totalSum.getDiseasePrevention() + vo.getDiseasePrevention());
            totalSum.setExpertTraining(Objects.isNull(totalSum.getExpertTraining()) ? vo.getExpertTraining() : totalSum.getExpertTraining() + vo.getExpertTraining());
            totalSum.setThirdPartyService(Objects.isNull(totalSum.getThirdPartyService()) ? vo.getThirdPartyService() : totalSum.getThirdPartyService() + vo.getThirdPartyService());
            totalSum.setOtherPayment(Objects.isNull(totalSum.getOtherPayment()) ? vo.getOtherPayment() : totalSum.getOtherPayment() + vo.getOtherPayment());
            totalSum.setPaymentTotal(Objects.isNull(totalSum.getPaymentTotal()) ? vo.getPaymentTotal() : totalSum.getPaymentTotal() + vo.getPaymentTotal());
            totalSum.setCityRecovered(Objects.isNull(totalSum.getCityRecovered()) ? vo.getCityRecovered() : totalSum.getCityRecovered() + vo.getCityRecovered());
            totalSum.setDistrictRecovered(Objects.isNull(totalSum.getDistrictRecovered()) ? vo.getDistrictRecovered() : totalSum.getDistrictRecovered() + vo.getDistrictRecovered());
        }

        // 替换为分组统计数据并添加总计行
        List<HaikouIncomeExpenditureExportVO> finalExportList = new ArrayList<>(groupSumMap.values());
        finalExportList.add(totalSum);

        // 5. 导出Excel（配置标题与合并表头）
        ExportParams exportParams = new ExportParams();
        exportParams.setTitle("海口市病媒生物防制工作经费收支情况统计表");
        exportParams.setSheetName("收支数据");
        exportParams.setType(ExcelType.HSSF);

        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, HaikouIncomeExpenditureExportVO.class, finalExportList);

        // 6. 写入响应流
        try (OutputStream out = response.getOutputStream()) {
            workbook.write(out);
            System.out.println("数据已导出");
        }
    }*/

    /*@PostMapping("export-haikou2")
    public void exportHaikou2(@RequestBody @Validated IncomeExpenditurePageDTO dto, HttpServletResponse response) throws Exception {
        System.out.println("进来了export-haikou");
        // 1. 日期参数处理与统计说明
        if (dto.hasEmptyDates()) {
            dto.initDefaultDates();
        }
        String startStr = DateUtil.format(dto.getStartDate(), "yyyy年MM月dd日");
        String endStr = DateUtil.format(dto.getEndDate(), "yyyy年MM月dd日");

        // 2. 查询原始数据（Long类型，万元分）
        List<IncomeExpenditure> dataList = incomeExpenditureService.getAllData();
        if (dataList.isEmpty()) {
            throw new RuntimeException("无数据可导出");
        }

        // 3. 按区域分组，同一区域内年度倒序
        Map<String, List<IncomeExpenditure>> districtGroup = dataList.stream()
                .sorted(Comparator.comparing(IncomeExpenditure::getYear).reversed())
                .collect(Collectors.groupingBy(IncomeExpenditure::getDistrict));

        // 4. 转换为VO（直接映射Long类型的万元分数据）
        List<HaikouIncomeExpenditureExportVO> exportList = new ArrayList<>();
        HaikouIncomeExpenditureExportVO totalSum = new HaikouIncomeExpenditureExportVO();
        totalSum.setDistrict("合计");
        totalSum.setYear(null);

        for (Map.Entry<String, List<IncomeExpenditure>> entry : districtGroup.entrySet()) {
            String district = entry.getKey();
            for (IncomeExpenditure entity : entry.getValue()) {
                HaikouIncomeExpenditureExportVO vo = new HaikouIncomeExpenditureExportVO();
                // 基础字段
                vo.setDistrict(district);
                vo.setYear(entity.getYear()); // 年份（自动格式化为“2024年度”）

                // 直接映射原始Long类型数据（万元分）
                vo.setCityAllocated(entity.getCityAllocated());
                vo.setDistrictAllocated(entity.getDistrictAllocated());
                vo.setOtherFunds(entity.getOtherFunds());
                vo.setFundsSourceTotal(entity.getTotalFunds());
                vo.setPurchaseMaintain(entity.getPurchaseMaintain());
                vo.setPurchaseEquipment(entity.getPurchaseEquipment());
                vo.setDiseasePrevention(entity.getDiseasePrevention());
                vo.setExpertTraining(entity.getExpertTraining());
                vo.setThirdPartyService(entity.getThirdPartyService());
                vo.setOtherPayment(entity.getOtherPayment());
                vo.setPaymentTotal(entity.getTotalPayment());
                vo.setCityRecovered(entity.getCityRecovered());
                vo.setDistrictRecovered(entity.getDistrictRecovered());

                exportList.add(vo);
                // 累加总合计（按万元分累加，最终由注解格式化）
                accumulateTotal(totalSum, vo);
            }
        }
        exportList.add(totalSum); // 添加总合计行

        // 5. 配置导出参数
        ExportParams exportParams = new ExportParams();
        exportParams.setTitle("海口市病媒生物防制工作经费收支情况统计表");
        exportParams.setSecondTitle("统计时间：" + startStr + "至" + endStr);
       // exportParams.setThirdTitle("单位：万元"); // 明确单位
        exportParams.setSheetName("收支数据");
        exportParams.setType(ExcelType.HSSF);
        //exportParams.setMergeVertical(true); // 合并“市辖区”列相同内容


        // 6. 导出Excel
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, HaikouIncomeExpenditureExportVO.class, exportList);

        // 7. 写入响应流
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        String fileName = URLEncoder.encode("海口市病媒生物防制工作经费收支情况统计表_" + DateUtil.format(new Date(), "yyyyMMdd"), "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        try (OutputStream out = response.getOutputStream()) {
            workbook.write(out);
            System.out.println("数据已导出");
        }
    }
*/
    // 累加Long类型的合计（万元分，null按0处理）
/*    private void accumulateTotal(HaikouIncomeExpenditureExportVO total, HaikouIncomeExpenditureExportVO vo) {
        total.setCityAllocated(addLong(total.getCityAllocated(), vo.getCityAllocated()));
        total.setDistrictAllocated(addLong(total.getDistrictAllocated(), vo.getDistrictAllocated()));
        total.setOtherFunds(addLong(total.getOtherFunds(), vo.getOtherFunds()));
        total.setFundsSourceTotal(addLong(total.getFundsSourceTotal(), vo.getFundsSourceTotal()));
        total.setPurchaseMaintain(addLong(total.getPurchaseMaintain(), vo.getPurchaseMaintain()));
        total.setPurchaseEquipment(addLong(total.getPurchaseEquipment(), vo.getPurchaseEquipment()));
        total.setDiseasePrevention(addLong(total.getDiseasePrevention(), vo.getDiseasePrevention()));
        total.setExpertTraining(addLong(total.getExpertTraining(), vo.getExpertTraining()));
        total.setThirdPartyService(addLong(total.getThirdPartyService(), vo.getThirdPartyService()));
        total.setOtherPayment(addLong(total.getOtherPayment(), vo.getOtherPayment()));
        total.setPaymentTotal(addLong(total.getPaymentTotal(), vo.getPaymentTotal()));
        total.setCityRecovered(addLong(total.getCityRecovered(), vo.getCityRecovered()));
        total.setDistrictRecovered(addLong(total.getDistrictRecovered(), vo.getDistrictRecovered()));
    }

    // Long累加（null按0处理）
    private Long addLong(Long total, Long current) {
        return (total == null ? 0L : total) + (current == null ? 0L : current);
    }*/
}
